package com.feixiang.springbootinit.service;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.feixiang.springbootinit.common.ErrorCode;
import com.feixiang.springbootinit.constant.WxConstant;
import com.feixiang.springbootinit.exception.BusinessException;
import com.feixiang.springbootinit.exception.ThrowUtils;
import com.feixiang.springbootinit.mapper.QwMessageMapper;
import com.feixiang.springbootinit.model.entity.wechat.*;
import com.feixiang.springbootinit.model.enums.SessionArchiveMsgActionEnum;
import com.feixiang.springbootinit.model.vo.SessionArchive.MessageVO;
import com.feixiang.springbootinit.model.vo.wechat.MsgVO;
import com.feixiang.springbootinit.utils.SessionArchiveUtil;
import com.tencent.wework.Finance;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.File;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Service
@Slf4j
public class SessionArchiveService {
    @Value("${file-upload-path.win}")
    //存入文件的路径
    private String fileUploadPath;
    @Value("${file-mapping-url.win}")
    //文件映射路径
    private String fileMappingUrl;
    @Resource
    private QwMessageService messageService;
    @Resource
    private QwMessageMapper messageMapper;
    @Resource
    private QwImageMessageService imageMessageService;
    @Resource
    private QwVoiceMessageService voiceMessageService;
    @Resource
    private QwFileMessageService fileMessageService;
    @Resource
    private QwTextMessageService textMessageService;
    @Resource
    private QwRecallMessageService recallMessageService;
    /**
     * 初始化 SDK
     */
    long sdk;
    /**
     * 获取会话存档数据
     *
     * @param startSeq
     * @return
     */
    public String getChatData(Long startSeq) {
        long limit = 100L;
        long slice = Finance.NewSlice();
        int ret = Finance.GetChatData(sdk, startSeq, limit, null, null, 1000, slice);
        if (ret != 0) {
            log.error("调用sdk拉取消息接口失败,失败消息为 ret = " + ret);
            Finance.FreeSlice(slice);
        }
        String s = Finance.GetContentFromSlice(slice);
        log.info("获取会话存档加密数据:{}", s);
        return s;
    }
    /**
     * 拉取解密chatData数据
     *
     * @param contentResult 拉取到的JSON原文
     */
    @Transactional
    public List<QwMessage> decodeChatData(String contentResult) {
        // 1.基础信息解析
        List<QwMessage> messageList = new ArrayList<>();
       ThrowUtils.throwIf(StrUtil.isBlank(contentResult), ErrorCode.PARAMS_ERROR, "拉取数据为空");
        MessagePullResponse messagePullResponse = JSONUtil.toBean(contentResult, MessagePullResponse.class);
        if (messagePullResponse == null || messagePullResponse.getChatdata() == null) {
            return Collections.emptyList();
        }
        if (messagePullResponse.getErrcode() != 0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "获取会话存档数据失败，错误码：" + messagePullResponse.getErrcode() + "，错误信息：" + messagePullResponse.getErrmsg());
        }
        List<ChatData> chatdataList = messagePullResponse.getChatdata();
        log.info("获取会话存档加密数据:{}", chatdataList);
        // 2.解密数据
        //拿到PK1私钥
        PrivateKey privateKey = SessionArchiveUtil.getPrivateKey(WxConstant.PRIVKEY);
        for (ChatData chatData : chatdataList) {
            try {
                //存档内容解密,解密ChatData数据
                String RandomKey = SessionArchiveUtil.decrptyRandomKey(privateKey, chatData.getEncryptRandomKey());
                //得到解密的明文数据
                String decryptMsg = SessionArchiveUtil.decryptData(sdk, RandomKey, chatData.getEncryptChatMsg());
                //获取到解密数据,转换成VO对象 => 对应企微给的结构
                MsgVO msgVO = JSONUtil.toBean(decryptMsg, MsgVO.class);
                ThrowUtils.throwIf(msgVO == null, ErrorCode.SYSTEM_ERROR, "解密消息失败");
                //log.info("获取会话存档magvo消息:{}", msgVO);
                //3.存档内容处理，进行写库
                //构造写库对象,区分消息类型，系统所有存档的消息都要保存
                //构造基本信息对象
                QwMessage message = new QwMessage();
//              switch (msgVO.getMsgtype()) {
//                    case "text":
//                        //处理文本消息,对文本消息进行获取，其他类型消息直接返回全部字符串
//                        break;
//                    case "image":
//                        break;
//                    case "weapp":
//                        break;
//                    case "file":
//                        break;
//                    case "video":
//                        break;
//                    case "voice":
//                        break;
//                    case "chatrecord":
//                    case "link":
//                    default:
//                }
                if (msgVO.getAction().equals(SessionArchiveMsgActionEnum.SWITCH.getCode())) { //切换企业日志
                    message.setSeq(chatData.getSeq());
                    message.setMsgId(msgVO.getMsgid());
                    message.setAction(msgVO.getAction());
                    message.setMsgtime(DateUtil.date(msgVO.getTime()));
                    message.setContent(decryptMsg);
                    message.setMsgtype("switch");
                } else if (msgVO.getAction().equals(SessionArchiveMsgActionEnum.SEND.getCode())) { //发送消息
                    message.setSeq(chatData.getSeq());
                    message.setMsgId(msgVO.getMsgid());
                    message.setAction(msgVO.getAction());
                    message.setFromId(msgVO.getFrom());
                    message.setMsgtype(msgVO.getMsgtype());
                    message.setTolist(JSONUtil.toJsonStr(msgVO.getTolist()));
                    message.setRoomid(msgVO.getRoomid());//消息发送时间戳，utc时间，ms单位
                    Date date = DateUtil.date(msgVO.getMsgtime());
                    message.setMsgtime(date);
                    message.setCreatedTime(new Date());
                    message.setContent(decryptMsg);
                } else if (msgVO.getAction().equals(SessionArchiveMsgActionEnum.RECALL.getCode())) { //撤回消息
                    message.setSeq(chatData.getSeq());
                    message.setMsgId(msgVO.getMsgid());
                    message.setAction(msgVO.getAction());
                    message.setFromId(msgVO.getFrom());
                    message.setMsgtype(msgVO.getMsgtype());
                    message.setTolist(JSONUtil.toJsonStr(msgVO.getTolist()));
                    message.setRoomid(msgVO.getRoomid());
                    message.setMsgtime(DateUtil.date(msgVO.getMsgtime()));
                    message.setCreatedTime(new Date());
                    message.setContent(decryptMsg);
                }
                messageService.save(message);
                log.info("获取会话存档基本消息情况:{}", message);
                //基础消息信息入库
                if (message.getMsgtype().equals("switch")) {
                    log.info("切换企业处理的信息：{}", message);
                    continue;
                }
                if (msgVO.getMsgtype().equals("text")) {
                    //文本消息处理，写入文本表
                    log.info("进行文本拉取处理");
                    QwTextMessage textMessage = new QwTextMessage();
                    textMessage.setMsgId(msgVO.getMsgid());
                    textMessage.setContent(msgVO.getText().getContent());
                    textMessage.setCreatedTime(new Date());
                    textMessageService.save(textMessage);
                } else if (msgVO.getMsgtype().equals("image")) {
                    // 图片消息处理,写入图片表
                    log.info("进行图片拉取处理");
                    //获取图片保存路径
                    String filePath = processFile(
                            msgVO.getImage().getSdkfileid(),
                            msgVO.getImage().getMd5sum(),
                            "png",
                            "image",
                            msgVO.getImage().getMd5sum()
                    );
                    //写库
                    QwImageMessage imageMessage = new QwImageMessage();
                    imageMessage.setMsgId(msgVO.getMsgid());
                    imageMessage.setMediaUrl(filePath);
                    imageMessage.setFileSize(msgVO.getImage().getFilesize());
                    imageMessage.setCreatedTime(new Date());
                    imageMessageService.save(imageMessage);
                } else if (msgVO.getMsgtype().equals("voice")) {
                    //语音消息处理，写入语音表
                    log.info("进行语音拉取处理");
                    //获取语音保存路径
                    String filePath = processFile(
                            msgVO.getVoice().getSdkfileid(),
                            msgVO.getVoice().getMd5sum(),
                            "mp3",
                            "voice",
                            msgVO.getVoice().getMd5sum()
                    );
                    //写库
                    QwVoiceMessage voiceMessage = new QwVoiceMessage();
                    voiceMessage.setMsgId(msgVO.getMsgid());
                    voiceMessage.setMediaUrl(filePath);
                    voiceMessage.setVoiceSize(msgVO.getVoice().getVoice_size());
                    voiceMessage.setPlayLength(msgVO.getVoice().getPlay_length());
                    voiceMessage.setCreatedTime(new Date());
                    voiceMessageService.save(voiceMessage);
                } else if (msgVO.getMsgtype().equals("file")) {
                    //文件消息处理，写入文件表
                    log.info("进行文件拉取处理");
                    //获取文件保存路径
                    String filePath = processFile(
                            msgVO.getFile().getSdkfileid(),
                            msgVO.getFile().getMd5sum(),
                            msgVO.getFile().getFileext(),
                            "file",
                            msgVO.getFile().getMd5sum()
                    );
                    //写库
                    QwFileMessage fileMessage = new QwFileMessage();
                    fileMessage.setMsgId(msgVO.getMsgid());
                    fileMessage.setMediaUrl(filePath);
                    fileMessage.setFileSize(msgVO.getFile().getFilesize());
                    fileMessage.setFileName(msgVO.getFile().getFilename());
                    fileMessage.setFileExt(msgVO.getFile().getFileext());
                    fileMessage.setCreatedTime(new Date());
                    fileMessageService.save(fileMessage);
                }else if (msgVO.getMsgtype().equals("revoke")) {
                    //撤回消息处理，写入撤回表
                    log.info("进行撤回消息处理");
                    //写库
                    QwRecallMessage recallMessage = new QwRecallMessage();
                    recallMessage.setMsgId(msgVO.getMsgid());
                    recallMessage.setRecallMsgId(msgVO.getRevoke().getPre_msgid());
                    recallMessage.setCreatedTime(new Date());
                    recallMessageService.save(recallMessage);
                }
                else {
                    //其他消息处理
                    log.info("获取会话存档其他消息:{}", msgVO);
                }
            } catch (Exception e) {
                // 收集失败情况数据
                e.printStackTrace();
                // 解密失败，取消执行正常情况不会遇到解密失败的问题]
                return Collections.emptyList();
            }
        }
        // 4.保存消息和失败任务
        //log.info("获取会话存档消息:{}", messageList);
        return messageList;
    }



    /**
     * 通用文件处理方法
     *
     * @param sdkFileId SDK文件ID
     * @param md5Sum 文件MD5
     * @param fileExt 文件扩展名
     * @param subDir 子目录（如image, voice等）
     * @param saveFileName 保存文件名（不带扩展名）
     * @return 保存的文件路径（使用正斜杠）
     */
    private String processFile(String sdkFileId, String md5Sum, String fileExt, String subDir, String saveFileName) {
        // 按日期生成路径
        String datePath = DateUtil.format(new Date(), "yyyy-MM-dd");
        String savePath = fileUploadPath + File.separator + subDir + File.separator + datePath;

        // 创建目录（如果不存在）
        File dir = new File(savePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 构建文件路径
        String fileName = saveFileName + "." + fileExt;
        String filePath = savePath + File.separator + fileName;

        // 下载文件
        SessionArchiveUtil.GetMediaData(sdk, sdkFileId, null, null, 1000L, filePath);

        // 将文件路径中的反斜杠转换为正斜杠
        return filePath.replace("\\", "/");
    }
















    /**
     * 查询数据库的会消息记录(mysql)
     */
    public List<MessageVO> selectChatData(String senderId, String recipientId) {
        List<QwMessage> messages = messageMapper.selectList(new QueryWrapper<QwMessage>()
                .lambda()
                .and(w -> w.eq(QwMessage::getFromId, senderId)
                        .apply("JSON_CONTAINS(tolist, CONCAT('\"', {0}, '\"'))", recipientId))
                .or(w -> w.eq(QwMessage::getFromId, recipientId)
                        .apply("JSON_CONTAINS(tolist, CONCAT('\"', {0}, '\"'))", senderId))
                .eq(QwMessage::getIsDeleted, 0)
                .orderByAsc(QwMessage::getMsgtime)
        );
        //拿到数据库的消息集合，进行转换为VO对象
        List<MessageVO> messageVOList = messages.stream().map(message -> {
            MessageVO messageVO = new MessageVO();
            //得到真正的明文消息,进行转换
            MsgVO msgVO = JSONUtil.toBean(message.getContent(), MsgVO.class);
            BeanUtils.copyProperties(message, messageVO);
            //1.如果类型是文本
            if (message.getMsgtype().equals("text")) {
                messageVO.setContent(msgVO.getText().getContent());//得到文本消息
                messageVO.setTolist(msgVO.getTolist());
            }
            //2.如果类型是图片
            //需要去图片表获取图片地址
            else if (message.getMsgtype().equals("image")) {
                QwImageMessage imagemessage = imageMessageService.lambdaQuery().eq(QwImageMessage::getMsgId, message.getMsgId()).one();
                messageVO.setContent(imagemessage.getMediaUrl());
            }
            return messageVO;
        }).collect(Collectors.toList());
        return messageVOList;
    }

}
